﻿#nullable disable

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Runtime.CompilerServices;

namespace System.Reflection
{
    #region Type 相关扩展

    /// <summary>
    /// Type 相关扩展
    /// </summary>
    public static class TypeExtensions
    {
        #region 获取成员元数据的Description特性描述信息

        /// <summary>
        ///     获取成员元数据的Description特性描述信息
        /// </summary>
        /// <param name="member">  成员元数据对象 </param>
        /// <param name="inherit"> 是否搜索成员的继承链以查找描述特性 </param>
        /// <returns> 返回Description特性描述信息，如不存在则返回成员的名称 </returns>
        public static string GetDescription(this MemberInfo member, bool inherit = true)
        {
            var desc = member.GetAttribute<DescriptionAttribute>(inherit);
            if (desc != null)
                return desc.Description;

            var displayName = member.GetAttribute<DisplayNameAttribute>(inherit);

            if (displayName != null)
                return displayName.DisplayName;
            var display = member.GetAttribute<DisplayAttribute>(inherit);

            return display != null ? display.Name : member.Name;
        }

        #endregion

        #region 从类型成员获取指定Attribute特性

        /// <summary>
        ///     从类型成员获取指定Attribute特性
        /// </summary>
        /// <typeparam name="T"> Attribute特性类型 </typeparam>
        /// <param name="memberInfo"> 类型类型成员 </param>
        /// <param name="inherit">    是否从继承中查找 </param>
        /// <returns> 存在返回第一个，不存在返回null </returns>
        public static T GetAttribute<T>(this MemberInfo memberInfo, bool inherit = true) where T : Attribute
        {
            var attributes = memberInfo.GetCustomAttributes(typeof(T), inherit);
            return attributes.FirstOrDefault() as T;
        }

        #endregion

        #region 从类型成员获取指定Attribute特性

        /// <summary>
        ///     从类型成员获取指定Attribute特性
        /// </summary>
        /// <typeparam name="T"> Attribute特性类型 </typeparam>
        /// <param name="memberInfo"> 类型类型成员 </param>
        /// <param name="inherit">    是否从继承中查找 </param>
        /// <returns> 返回所有指定Attribute特性的数组 </returns>
        public static T[] GetAttributes<T>(this MemberInfo memberInfo, bool inherit = true) where T : Attribute
            => memberInfo.GetCustomAttributes(typeof(T), inherit).Cast<T>().ToArray();

        #endregion

        #region 检查指定指定类型成员中是否存在指定的Attribute特性

        /// <summary>
        ///     检查指定指定类型成员中是否存在指定的Attribute特性
        /// </summary>
        /// <typeparam name="T">要检查的Attribute特性类型</typeparam>
        /// <param name="memberInfo">要检查的类型成员</param>
        /// <param name="inherit">是否从继承中查找</param>
        /// <returns>是否存在</returns>
        public static bool HasAttribute<T>(this MemberInfo memberInfo, bool inherit = true) where T : Attribute
            => memberInfo.IsDefined(typeof(T), inherit);

        #endregion

        #region 判断类型是否为匿名类型

        /// <summary>
        ///     判断类型是否为匿名类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsAnonymousType(this Type type)
            => Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)
               && type.IsGenericType && type.Name.Contains("AnonymousType")
               && type.Name.StartsWith("<>")
               && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic;

        #endregion

        #region 判断当前类型是否可由指定类型派生

        /// <summary>
        ///     判断当前类型是否可由指定类型派生
        /// </summary>
        public static bool IsDeriveClassFrom<TBaseType>(this Type type, bool canAbstract = false)
            => IsDeriveClassFrom(type, typeof(TBaseType), canAbstract);

        #endregion

        #region 判断当前类型是否可由指定类型派生

        /// <summary>
        ///     判断当前类型是否可由指定类型派生
        /// </summary>
        public static bool IsDeriveClassFrom(this Type type, Type baseType, bool canAbstract = false)
            => type.IsClass && (canAbstract || !type.IsAbstract) && type.IsBaseOn(baseType);

        #endregion

        #region 判断类型是否为Nullable类型

        /// <summary>
        ///     判断类型是否为Nullable类型
        /// </summary>
        /// <param name="type"> </param>
        /// <returns> </returns>
        public static bool IsNullableType(this Type type)
            => type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);

        #endregion

        #region 由类型的Nullable类型返回实际类型

        /// <summary>
        ///     由类型的Nullable类型返回实际类型
        /// </summary>
        /// <param name="type"> 要处理的类型对象 </param>
        /// <returns> </returns>
        public static Type GetNonNullableType(this Type type)
            => IsNullableType(type) ? type.GetGenericArguments()[0] : type;

        #endregion

        #region 通过类型转换器获取Nullable类型的基础类型

        /// <summary>
        ///     通过类型转换器获取Nullable类型的基础类型
        /// </summary>
        /// <param name="type"> 要处理的类型对象 </param>
        /// <returns> </returns>
        public static Type GetUnNullableType(this Type type)
        {
            if (IsNullableType(type))
            {
                var nullableConverter = new NullableConverter(type);
                return nullableConverter.UnderlyingType;
            }

            return type;
        }

        #endregion

        #region 返回当前类型是否是指定基类的派生类

        /// <summary>
        ///     返回当前类型是否是指定基类的派生类
        /// </summary>
        /// <param name="type">当前类型</param>
        /// <param name="baseType">要判断的基类型</param>
        /// <returns></returns>
        public static bool IsBaseOn(this Type type, Type baseType)
        {
            if (baseType.IsGenericTypeDefinition) return baseType.IsGenericAssignableFrom(type);
            return baseType.IsAssignableFrom(type);
        }

        #endregion

        #region 返回当前类型是否是指定基类的派生类

        /// <summary>
        ///     返回当前类型是否是指定基类的派生类
        /// </summary>
        /// <typeparam name="TBaseType">要判断的基类型</typeparam>
        /// <param name="type">当前类型</param>
        /// <returns></returns>
        public static bool IsBaseOn<TBaseType>(this Type type)
        {
            var baseType = typeof(TBaseType);
            return type.IsBaseOn(baseType);
        }

        #endregion

        #region 判断当前泛型类型是否可由指定类型的实例填充

        /// <summary>
        ///     判断当前泛型类型是否可由指定类型的实例填充
        /// </summary>
        /// <param name="genericType">泛型类型</param>
        /// <param name="type">指定类型</param>
        /// <returns></returns>
        public static bool IsGenericAssignableFrom(this Type genericType, Type type)
        {
            if (genericType is null) throw new ArgumentNullException(nameof(genericType));
            if (type is null) throw new ArgumentNullException(nameof(type));
            if (!genericType.IsGenericType) throw new ArgumentException("该功能只支持泛型类型的调用，非泛型类型可使用 IsAssignableFrom 方法。");

            var allOthers = new List<Type> { type };
            if (genericType.IsInterface) allOthers.AddRange(type.GetInterfaces());

            foreach (var other in allOthers)
            {
                var cur = other;
                while (cur != null)
                {
                    if (cur.IsGenericType) cur = cur.GetGenericTypeDefinition();
                    if (cur.IsSubclassOf(genericType) || cur == genericType) return true;
                    cur = cur.BaseType;
                }
            }

            return false;
        }

        #endregion
    }

    #endregion
}